package classloader;

import java.io.*;

/**
 * @author zheng9feng
 * @Description 自定义类加载器
 * @Date 2021/1/6 00:07
 */
public class CustomClassLoader extends ClassLoader {
	/**
	 * class文件所在目录路径
	 */
	private String path;
	
	public CustomClassLoader() {
		super(null);
	}
	
	public void setPath(String path) {
		this.path = path;
	}
	
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		// 判断对应class是否被加载过
		Class<?> loadedClass = findLoadedClass(name);
		if (loadedClass != null) {
			return loadedClass;
		}
		
		// 判断文件是否存在
		String fullPath = path + name.replace(".", "/") + ".class";
		File file = new File(fullPath);
		if (!file.exists()) {
			throw new ClassNotFoundException(name);
		}
		
		byte[] classBytes = getClassBytes(file);
		Class<?> aClass = defineClass(name, classBytes, 0, classBytes.length);
		
		// resolveClass(aClass);
		return aClass;
	}
	
	/**
	 * 获取class文件字节数组,用于定义Class对象
	 *
	 * @param file
	 * @return
	 */
	private byte[] getClassBytes(File file) {
		// 初始化
		byte[] bytes = null;
		
		ByteArrayOutputStream byteArrayOutputStream = null;
		try (FileInputStream fileInputStream = new FileInputStream(file)) {
			byteArrayOutputStream = new ByteArrayOutputStream();
			
			// way1
			// 用于缓存的数组大小可以设置为1或文件实际的字节大小
			// 否则会报:Exception in thread "main" java.lang.ClassFormatError: Extra bytes at the end of class file classloader/Demo1
			// bytes = new byte[fileInputStream.available()];
			// int len = -1;
			// while ((len = fileInputStream.read(bytes)) != -1) {
			// 	byteArrayOutputStream.write(bytes, 0, bytes.length);
			// }
			
			// way2:直接按字节读取
			int read = 0;
			while ((read = fileInputStream.read()) != -1) {
				byteArrayOutputStream.write(read);
			}
			
			return byteArrayOutputStream.toByteArray();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (byteArrayOutputStream != null) {
				try {
					byteArrayOutputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}
	
	public static void main(String[] args) throws ClassNotFoundException {
		String osName = System.getProperty("os.name");
		System.out.println("os name is " + osName);
		// /Users/zheng9feng/simple-framework-handwriting/simple-tomcat/target/test-classes/
		// D:\zone\document\git-repos\simple-framework-handwriting\simple-tomcat\target\test-classes\
		System.out.println("---------------------------------------");
		System.out.println("需要被加载的class文件所在目录:" + args[0]);
		CustomClassLoader customClassLoader = new CustomClassLoader();
		customClassLoader.setPath(args[0]);
		
		Class<?> aClass = customClassLoader.findClass("classloader.Demo1");
		System.out.println("---------------------------------------");
		System.out.println(aClass.getClassLoader());
	}
}
